#include <cmath>
#include "GameEngine.h"
#include "Constants.h"
#include "RessourceManager.h"
#include "Collision.h"
#include "PlayerEntity.h"
#include "Application.h"

GameEngine::GameEngine(Application* app) : Engine(app)
{
    Data::populateEntities(&factory);
    effectLayer.setSize(sf::Vector2f(WINDOW_WIDTH, WINDOW_HEIGHT));
}

void GameEngine::onLaunch()             // Things to do at game launch, like loading textures and so.
{
    for(int i=0; i<sf::Keyboard::KeyCount; i++)
    {
        keys[i] = false;
    }

    level.loadFromFile("map1.map");
    player = static_cast<PlayerEntity*>(factory.create("player"));
    player->setX(4);
    player->setY(1);
    player->setHUD(&hud);
    spawn("zombie", 5, 5);
    spawn("heart", 9, 5);
    effectLayer.setFillColor(sf::Color(0,0,0,0));
    gameOver = 0;
    hud.updateLife(100,100);
}

void GameEngine::onEvent(sf::Event* event)
{
    if(event->type == sf::Event::KeyPressed)
    {
        if(event->key.code == sf::Keyboard::Escape && !gameOver)
            app->setActiveMode(Application::MAIN_MENU);

        keys[event->key.code] = true;
    }
    else if(event->type == sf::Event::KeyReleased)
    {
        keys[event->key.code] = false;
    }
}

void GameEngine::onTick()
{
    if(!gameOver)
    {
        if(keys[sf::Keyboard::Up])
            player->setMotionY(0.12f);

        if(keys[sf::Keyboard::Right])
            player->setMotionX(0.3f);

        if(keys[sf::Keyboard::Left])
            player->setMotionX(-0.3f);

        if(keys[sf::Keyboard::I])
            spawn("heart", player->getX(), player->getY() + 3);

        if(keys[sf::Keyboard::R])
            onReload();
    }
    else
    {
        gameOver++;
        int alpha = (gameOver - 120) * 3;
        if(alpha < 0)
            alpha = 0;

        if(alpha > 255)
            alpha = 255;

        effectLayer.setFillColor(sf::Color(0,0,0,alpha));
    }

    Collision::resolve(player, &level);

    for(std::list<Entity*>::iterator it = entities.begin(); it != entities.end();)
    {
        if(!(*it)->doesNeedRemoval())
        {
            Collision::resolve((*it), &level);
            if((*it)->collide(player))
                (*it)->onCollide(player);

            ++it;

        }
        else
        {
            delete *it;
            it = entities.erase(it);
        }
    }

    if(!player->isAlive() && !gameOver)
    {
        gameOver = 1;
    }
    if(gameOver == 300)
        app->setActiveMode(Application::GAME_OVER);
}

void GameEngine::onRender(sf::RenderWindow* window)
{
    renderer.aim(player->getX(), player->getY());
    renderer.render(window, &level);

    for(std::list<Entity*>::iterator it = entities.begin(); it != entities.end(); ++it)
        renderer.render(window, *it);

    renderer.render(window, player);
    hud.render(window);
    window->draw(effectLayer);
}

void GameEngine::onClose()
{
    delete player;
    for(std::list<Entity*>::iterator it = entities.begin(); it != entities.end(); ++it)
    {
        delete *it;
    }
    entities.clear();

}

void GameEngine::spawn(std::string type, float x, float y)
{
    try
    {
        Entity* entity = factory.create(type);
        entity->setX(x);
        entity->setY(y);
        entities.push_back(entity);
    }
    catch(std::exception & e)
    {
        std::cerr << e.what() << std::endl;
    }
}

